﻿namespace FFF.Test.DataAccess.Framework
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data;
    using System.Data.Common;
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Threading;
    using System.Threading.Tasks;
    using Abp.Dependency;
    using Abp.Domain.Entities;
    using Abp.EntityFrameworkCore;
    using Abp.Runtime.Caching;
    using Microsoft.AspNetCore.Http;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Diagnostics;
    using Microsoft.EntityFrameworkCore.Metadata.Builders;
    using Microsoft.EntityFrameworkCore.Metadata.Internal;
    using Microsoft.Extensions.Configuration;
    using FFF.Test.DataAccess.Framework.Configuration;
    using FFF.Test.Entity;
    using FFF.Test.Entity.Demo;
    using FFF.Test.Entity.Demo.View;
    using FFF.Test.Entity.Framework.Entity;
    using FFF.Test.Entity.Framework.View;
    using FFF.Test.Entity.FW.Proc;
    using FFF.Test.Util.Configuration;
    using FFF.Test.Util.Consts;
    using Ydm.Extensions;
    using Ydm.Helper;
    using Z.EntityFramework.Extensions;

    /// <summary>
    /// dbcontext类
    /// </summary>
    public partial class MyDbContext : AbpDbContext
    {
        private static EFCommandInterceptor _commandInterceptor = new EFCommandInterceptor();
        private static EFConnectionInterceptor _conectionInterceptor = new EFConnectionInterceptor();
        private static EFTransactionInterceptor _transInterceptor = new EFTransactionInterceptor();
        private readonly IIocResolver _iocResolver;

        /// <summary>
        /// Initializes a new instance of the <see cref="MyDbContext"/> class.
        /// </summary>
        /// <param name="options">生成db对象的配置对象</param>
        /// <param name="iocResolver">依赖注入</param>
        public MyDbContext(DbContextOptions<MyDbContext> options, IIocResolver iocResolver)
            : base(options)
        {
            this._iocResolver = iocResolver;
            base.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

            DbFilterConfiguration.InitContextFilter(this._iocResolver, this);

            //if (this.Database.EnsureCreated())
            //{
            //    DescConfiguration.Excute(this); // 设置数据库字段的描述信息
            //}

            // DescConfiguration.Excute(this); // 设置数据库字段的描述信息

            // 拦截connection
            //this.BindInterceptor(_conectionInterceptor);

            //// 拦截command
            //this.BindInterceptor(_commandInterceptor);

            //// 拦截事务
            //this.BindInterceptor(_transInterceptor);
        }

        /// <summary>
        /// 获取配置类参数
        /// </summary>
        /// <param name="bizOptionCode">配置类参数编码</param>
        /// <param name="scopeGUID">范围GUID 不传默认集团级的</param>
        /// <returns>配置类参数的值</returns>
        public async Task<string> GetConfigBiz(string bizOptionCode, Guid? scopeGUID = null)
        {
            var value = await this.ViewCFBizConfigOption
                .Where(x => x.BizOptionCode == bizOptionCode && x.BizOptionScopeGUID == scopeGUID)
                .Select(x => x.BizOptionValue)
                .FirstOrDefaultAsync();
            return value;
        }

        /// <summary>
        /// 获取 流水号 db.GetFlowNumber("SH_Device")
        /// </summary>
        /// <param name="tableName">表的名称</param>
        /// <returns>表的ID值</returns>
        public string GetFlowNumber(string tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            UspFWGetFlowNumber uspFWGetFlowNumber = new UspFWGetFlowNumber()
            {
                @TableName = tableName
            };
            Dictionary<string, object> outObjs = new Dictionary<string, object>(); // 接收输出参数
            uspFWGetFlowNumber.ExecuteNonQuery(outObjs);
            return outObjs["@OutNo"].ToString();
        }

        /// <summary>
        /// 执行给定的命令
        /// </summary>
        /// <param name="sql">命令字符串</param>
        /// <param name="parameters">要应用于命令字符串的参数</param>
        /// <returns>执行命令后由数据库返回的结果</returns>
        public async Task<int> ExecuteAsync(string sql, params object[] parameters)
        {
            return await this.Database.ExecuteSqlCommandAsync(sql, parameters);
        }

        /// <summary>
        /// 获取DataTable
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters">要应用于命令字符串的参数</param>
        /// <returns>dataTable</returns>
        public async Task<DataTable> GetDataTableAsync(string sql, params object[] parameters)
        {
            DbCommand cmd = this.Database.GetDbConnection().CreateCommand();
            if (parameters.Length > 0)
            {
                cmd.Parameters.AddRange(parameters);
            }

            cmd.CommandText = sql;

            if (cmd.Connection.State == ConnectionState.Closed)
            {
                await cmd.Connection.OpenAsync();
            }
            else
            {
                if (this.Database.CurrentTransaction != null)
                {
                    throw new ArgumentException("请将APPService添加特性 [UnitOfWork(isTransactional: false)],才能使用该方法");

                    //this.Database.CommitTransaction();
                    //await cmd.Connection.OpenAsync();
                }
            }

            DataTable table = new DataTable();
            DbDataReader reader = await cmd.ExecuteReaderAsync();
            table.Load(reader);

            return table;
        }

        /// <summary>
        /// 执行sqlExecuteScalar
        /// </summary>
        /// <typeparam name="T">返回的类型</typeparam>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters">SqlParameter 参数</param>
        /// <returns>返回的传入的类型</returns>
        public async Task<T> ExecuteScalarAsync<T>(string sql, params SqlParameter[] parameters)
        {
            DbCommand cmd = this.Database.GetDbConnection().CreateCommand();
            if (parameters.Length > 0)
            {
                cmd.Parameters.AddRange(parameters);
            }

            cmd.CommandText = sql;
            if (cmd.Connection.State == ConnectionState.Closed)
            {
                await cmd.Connection.OpenAsync();
            }
            else
            {
                if (this.Database.CurrentTransaction != null)
                {
                    throw new ArgumentException("请将APPService接口添加特性 [UnitOfWork(isTransactional: false)],才能使用该方法");

                    //this.Database.CommitTransaction();
                    //await cmd.Connection.OpenAsync();
                }
            }

            object obj = await cmd.ExecuteScalarAsync();

            // cmd.Connection.Close();
            return (T)obj;
        }

        /// <summary>
        /// 根据sql查询集合
        /// </summary>
        /// <typeparam name="T">dto类</typeparam>
        /// <param name="sql">sql</param>
        /// <param name="parameters">sql参数</param>
        /// <returns>TDto的集合</returns>
        public async Task<List<T>> QueryListAsync<T>(string sql, params SqlParameter[] parameters)
            where T : class, new()
        {
            DataTable dt = await this.GetDataTableAsync(sql, parameters);
            return dt.ToList<T>();
        }

        /// <summary>
        /// 保存前的修改值
        /// </summary>
        /// <returns>影响的条数</returns>
        public override int SaveChanges()
        {
            this.BeforeSaveChange();
            return base.SaveChanges();
        }

        /// <summary>
        /// 保存异步实现
        /// </summary>
        /// <param name="cancellationToken">取消保存</param>
        /// <returns>保存设置</returns>
        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            this.BeforeSaveChange();
            return base.SaveChangesAsync();
        }

        /// <summary>
        /// 配置数据库的映射
        /// </summary>
        /// <param name="modelBuilder">映射Buildder</param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // DataSeedConfiguration.Seed(modelBuilder); // 初始化数据
            IEnumerable<Microsoft.EntityFrameworkCore.Metadata.IMutableEntityType> entityTypes = modelBuilder.Model.GetEntityTypes();
            foreach (Microsoft.EntityFrameworkCore.Metadata.IMutableEntityType entityType in entityTypes)
            {
                // DescConfiguration.InitColInfo(entityType); // 添加描述

                // 初始化 Isdelete全局过滤
                DbFilterConfiguration.InitGobalFilter(entityType, modelBuilder);

                ViewConfiguration.InitViews(entityType); // 初始化视图

                //if (entityType.ClrType.BaseType == typeof(BaseView<Guid>))
                //{
                //    _configureGlobalFiltersMethodInfo
                //        .MakeGenericMethod(entityType.ClrType)
                //        .Invoke(this, new object[] { modelBuilder });
                //}
            }

            // 配置entity
            Assembly configAssembly = Assembly.Load("FFF.Test.Entity");

            modelBuilder.ApplyConfigurationsFromAssembly(configAssembly);

            // modelBuilder.Query<ViewSHWorkOrder>().HasQueryFilter(q => q.Id == q.TenantId);

            // modelBuilder.Query<ViewSHWorkOrder>().HasQueryFilter(b => b.Id == System.Guid.NewGuid());

            //  modelBuilder.Entity<DemoClassEntity>().HasQueryFilter(b => EF.Property<byte>(b, "IsDeleted") == 0);

            //modelBuilder.Query<ViewSHWorkOrder>().HasQueryFilter(DbFilterConfiguration.InitTQuery<ViewSHWorkOrder>(this._iocResolver));

            //modelBuilder.Entity<DemoClassEntity>().HasMany(x => x.StudentEntities)
            //   .WithOne(x => x.ClassEntity).OnDelete(DeleteBehavior.Cascade);

            // 查询加入N'' 进行Unicode查询
            // modelBuilder.Query<ViewDemoStudentTe>().Property(t => t.StudentName).HasColumnType("NVARCHAR").HasMaxLength(250);
        }

        // private static MethodInfo _configureGlobalFiltersMethodInfo = typeof(MyDbContext).GetMethod(nameof(ConfigureGlobalFilters), BindingFlags.Instance | BindingFlags.Public);

        ///// <summary>
        ///// 设置过滤
        ///// </summary>
        ///// <typeparam name="T">变量</typeparam>
        ///// <param name="builder">buildder</param>
        //public void ConfigureGlobalFilters<T>(ModelBuilder builder)
        //    where T : BaseView<Guid>
        //{
        //    builder.Query<T>().HasQueryFilter(e => e.TenantId == this._tenantId);
        //}

        private void BeforeSaveChange()
        {
            base.ChangeTracker.DetectChanges();

            IEnumerable<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry> entries = base.ChangeTracker.Entries();

            // 处理Entity
            DbSaveConfiguration.BeforeSaveInitData(entries, this._iocResolver);
        }
    }
}
